/**
 * @file rtk_thread.c
 * @author LokLiang (lokliang@163.com)
 * @brief
 * @version 0.1
 * @date 2023-05-01
 *
 * @copyright Copyright (c) 2023
 *
 */

#include "prv_rtk_class.h"

static void _rtk_thread_init(rtk_thread_t *thread_handle,      // 线程句柄
                             struct rtk_thread_handle *thread, // 控制块地址
                             void (*entry)(void *arg),         // 线程入口地址
                             void *arg,                        // 线程入口参数
                             void *stack_base,                 // 栈内存地址
                             size_t stack_size,                // 栈大小（字节）
                             rtk_prior_t priority,             // 优先级（0 为最低，CONFIG_RTK_MAX_PRIORITY 为最高。若输入为负值则表示优先级为 (CONFIG_RTK_MAX_PRIORITY + 1 + priority)）
                             u8_t slice_ticks,                 // 被轮换的时间（值为 0 时不被轮换）
                             uint flag                         // @ref _RTK_THREAD_FLAG_HEAP _RTK_THREAD_FLAG_SYS _RTK_THREAD_FLAG_SEM
);
static void _rtk_thread_handler_start(void *arg); // 线程返回后的共同处理函数
static void _rtk_thread_exit(void);

rtk_thread_t *rtk_thread_init(rtk_thread_t *thread_handle, // 线程句柄（若取值为空则由内部自动分配，不允许使用局部变量）
                              const char *name,            // 线程名
                              void (*entry)(void *arg),    // 线程入口地址
                              void *arg,                   // 线程入口参数
                              void *stack_base,            // 栈内存地址
                              size_t stack_size,           // 栈大小（字节）
                              rtk_prior_t priority,        // 优先级（0 为最低，CONFIG_RTK_MAX_PRIORITY 为最高。若输入为负值则表示优先级为 (CONFIG_RTK_MAX_PRIORITY + 1 + priority)）
                              u8_t slice_ticks             // 被轮换的时间（值为 0 时不被轮换）
)
{
    _RTK_TRACE_ENTRY();

    rtk_thread_t *ret;

    do
    {
        struct rtk_thread_handle *thread = _rtk_name_malloc(name,
                                                            sizeof(*thread) +
                                                                (thread_handle == NULL ? sizeof(*thread_handle) : 0));
        if (thread == NULL)
        {
            ret = NULL;
            break;
        }
        if (thread_handle == NULL)
        {
            thread_handle = (rtk_thread_t *)&thread[1];
        }

        _rtk_thread_init(thread_handle, // rtk_thread_t *thread_handle,
                         thread,        // struct rtk_thread_handle *thread,
                         entry,         // void (*entry)(void *arg),
                         arg,           // void *arg,
                         stack_base,    // void *stack_base,
                         stack_size,    // size_t stack_size,
                         priority,      // rtk_prior_t priority,
                         slice_ticks,   // u8_t slice_ticks,
                         0              // @ref _RTK_THREAD_FLAG_HEAP _RTK_THREAD_FLAG_SYS _RTK_THREAD_FLAG_SEM
        );

        ret = thread_handle;

    } while (0);

    _RTK_TRACE_EXIT();
    return ret;
}

rtk_thread_t *rtk_thread_create(rtk_thread_t *thread_handle, // 线程句柄（若取值为空则由内部自动分配，不允许使用局部变量）
                                const char *name,            // 线程名
                                void (*entry)(void *arg),    // 线程入口地址
                                void *arg,                   // 线程入口参数
                                size_t stack_size,           // 栈大小（字节）
                                rtk_prior_t priority,        // 优先级（0 为最低，CONFIG_RTK_MAX_PRIORITY 为最高。若输入为负值则表示优先级为 (CONFIG_RTK_MAX_PRIORITY + 1 + priority)）
                                u8_t slice_ticks             // 被轮换的时间（值为 0 时不被轮换）
)
{
    _RTK_TRACE_ENTRY();
    _RTK_CHECK_ISR();

    rtk_thread_t *ret;

    do
    {
#if defined(CONFIG_RTK_STACK_CHECK)
        stack_size += sizeof(cm_rtk->MemDetector_Head);
#endif
        void *stack_base = rtk_heap_malloc_tail(stack_size, 0);
        if (stack_base == NULL)
        {
            ret = NULL;
            break;
        }

        struct rtk_thread_handle *thread = _rtk_name_malloc(name,
                                                            sizeof(*thread) +
                                                                (thread_handle == NULL ? sizeof(*thread_handle) : 0));
        if (thread == NULL)
        {
            rtk_heap_free(stack_base);
            ret = NULL;
            break;
        }

        if (thread_handle == NULL)
        {
            thread_handle = (rtk_thread_t *)&thread[1];
        }

        _rtk_thread_init(thread_handle,        // rtk_thread_t *thread_handle,
                         thread,               // struct rtk_thread_handle *thread,
                         entry,                // void (*entry)(void *arg),
                         arg,                  // void *arg,
                         stack_base,           // void *stack_base,
                         stack_size,           // size_t stack_size,
                         priority,             // rtk_prior_t priority,
                         slice_ticks,          // u8_t slice_ticks,
                         _RTK_THREAD_FLAG_HEAP // @ref _RTK_THREAD_FLAG_HEAP _RTK_THREAD_FLAG_SYS _RTK_THREAD_FLAG_SEM
        );

        ret = thread_handle;

    } while (0);

    _RTK_TRACE_EXIT();
    return ret;
}

rtk_err_t rtk_thread_delete(rtk_thread_t *thread_handle)
{
    _RTK_CHECK_ISR();

    struct rtk_thread_handle *thread;
    if (thread_handle == NULL)
    {
        thread = curr_thread_handle;
    }
    else
    {
        thread = thread_handle->hdl;
    }

    _RTK_CHECK_THREAD(&thread);

    if (thread == NULL)
    {
        return RTK_E_PARAM;
    }

    if (thread == curr_thread_handle) // 关闭当前线程为自己
    {
        if (cm_rtk->nest_sched != 0)
        {
            _RTK_WRN("Scheduler was not enabled when the thread was shut down: %s", thread->name);
        }

        cm_rtk->nest_sched = 0; // 强制恢复然后继续

        if (thread->mutex != NULL)
        {
            _RTK_WRN("Mutex was locked when the thread was shut down: %s", thread->name);

            do
            {
                rtk_mutex_unlock((rtk_mutex_t *)&thread->mutex); // 自动解除该线程的所有互斥量
            } while (thread->mutex != NULL);
        }

        rtk_sched_suspend();

        _rtk_list_atomic_deleted(thread);

        size_t nest_int = rtk_cpu_interrupt_save();
        slist_insert_tail(&cm_rtk->slist_delete, &thread->active_node);
        rtk_cpu_interrupt_restore(nest_int);

        cm_rtk->nest_sched = 0;

        _rtk_service_switch_to_tick(); // ==> _rtk_service_thread_idle()
    }
    else // 关闭另一线程
    {
        _RTK_TRACE_ENTRY();

        size_t sched_nest = rtk_sched_suspend();

        /* 释放共享资源权限 */
        while ((struct rtk_mutex_handle *)thread->mutex != NULL)
        {
            if (thread->mutex->hold_thread == thread) // 已锁定状态
            {
                thread->mutex->nest_incr = 1;
                _rtk_mutex_release_unlock(thread->mutex);
            }
            else // 未锁定状态
            {
                _rtk_list_atomic_suspend(thread);
                thread->mutex = thread->mutex->last_mutex;
            }
        }

        _rtk_list_atomic_deleted(thread);

        _rtk_service_thread_free(thread);

        rtk_sched_resume(sched_nest);

        _RTK_TRACE_EXIT();
    }

    return RTK_OK;
}

void _rtk_thread_init(rtk_thread_t *thread_handle,      // 线程句柄
                      struct rtk_thread_handle *thread, // 控制块地址
                      void (*entry)(void *arg),         // 线程入口地址
                      void *arg,                        // 线程入口参数
                      void *stack_base,                 // 栈内存地址
                      size_t stack_size,                // 栈大小（字节）
                      rtk_prior_t priority,             // 优先级（0 为最低，CONFIG_RTK_MAX_PRIORITY 为最高。若输入为负值则表示优先级为 (CONFIG_RTK_MAX_PRIORITY + 1 + priority)）
                      u8_t slice_ticks,                 // 被轮换的时间（值为 0 时不被轮换）
                      uint flag                         // @ref _RTK_THREAD_FLAG_HEAP _RTK_THREAD_FLAG_SYS _RTK_THREAD_FLAG_SEM
)
{
    memset(thread, 0, sizeof(*thread));

    /* 地址对齐 */
    size_t stack_end = (((size_t)stack_base + stack_size) / sizeof(size_t) * sizeof(size_t));
    stack_base = (void *)(((size_t)stack_base + sizeof(size_t) - 1) / sizeof(size_t) * sizeof(size_t));
    stack_size = stack_end - (size_t)stack_base;

    // 初始化线程栈
#if defined(CONFIG_RTK_STACK_CHECK)
    memset(stack_base, 0, stack_size);
    stack_size -= sizeof(cm_rtk->MemDetector_Head);
    thread->stack_remain = stack_size;
#endif

    if (cm_rtk->stack_grow_up)
    {
#if defined(CONFIG_RTK_STACK_CHECK)
        *((int *)&((uint8_t *)stack_base)[stack_size]) = _RTK_HEAP_DET_VALUE;
#endif

        void *stack_top = stack_base;
        void *stack_end = &((uint8_t *)stack_base)[stack_size];
        thread->pSP = rtk_cpu_stack_init(
            _rtk_thread_handler_start, // void *entry
            arg,                       // void *arg
            stack_top,                 // void *stack_top
            stack_end,                 // void *stack_end
            _rtk_thread_exit           // void *exit
        );
    }
    else
    {
#if defined(CONFIG_RTK_STACK_CHECK)
        *((int *)stack_base) = _RTK_HEAP_DET_VALUE;
        stack_base = &((uint8_t *)stack_base)[sizeof(cm_rtk->MemDetector_Head)];
#endif

        void *stack_top = &((uint8_t *)stack_base)[stack_size];
        void *stack_end = stack_base;
        thread->pSP = rtk_cpu_stack_init(
            _rtk_thread_handler_start, // void *entry
            arg,                       // void *arg
            stack_top,                 // void *stack_top
            stack_end,                 // void *stack_end
            _rtk_thread_exit           // void *exit
        );
    }

    thread->thread_handle = thread_handle;
    thread_handle->hdl = thread;

    // priority
    if (priority < 0)
    {
        priority = CONFIG_RTK_MAX_PRIORITY + 1 + priority;
    }
    if (priority > CONFIG_RTK_MAX_PRIORITY)
    {
        _RTK_WRN("priority = %d > CONFIG_RTK_MAX_PRIORITY. Now Set to %d", priority, CONFIG_RTK_MAX_PRIORITY);
        priority = CONFIG_RTK_MAX_PRIORITY;
    }

    /* 初始化控制块 */
    thread->control.entry = entry;             // 线程入口地址
    thread->control.priority = priority;       // 优先级（0 为最低，CONFIG_RTK_MAX_PRIORITY 为最高。若输入为负值则表示优先级为 (CONFIG_RTK_MAX_PRIORITY + 1 + priority)）
    thread->control.slice_ticks = slice_ticks; // 被轮换的时间（值为 0 时不被轮换）
    thread->stack_base = stack_base;           // 栈原始位置
    thread->stack_size = stack_size;           // 栈原始大小
    thread->curr_state = THREAD_STATE_SUSPEND;
    thread->curr_prior = priority;
    thread->slice_count = slice_ticks;
    thread->flag = flag;
    thread->name = rtk_heapk_key_base(thread);

    size_t sched_nest = rtk_sched_suspend();

    /* node */
    _rtk_list_init_node(&thread->state_node); // 线程状态链
    slist_init_node(&thread->critical_node);  // 在关中状态下操作的链
    slist_init_node(&thread->active_node);    // 所有有效的线程的节点
    dlist_init_node(&thread->sig_node);       // 等待信号的节点
    dlist_init_list(&thread->blocked_list);
    slist_init_list(&thread->slist_trace);

    /* 连接 */
    slist_insert_tail(&cm_rtk->slist_active, &thread->active_node);
    _rtk_list_atomic_resume(thread);

    rtk_sched_resume(sched_nest);
}

static void _rtk_thread_handler_start(void *arg)
{
    _RTK_TRACE_ENTRY();
    curr_thread_handle->control.entry(arg);
    rtk_thread_delete(NULL);
}

static void _rtk_thread_exit(void)
{
    _RTK_TRACE_ENTRY();
    rtk_thread_delete(NULL);
    SYS_LOG_ERR(""); // 线程返回后没有顺利调度
    for (;;)
    {
        ;
    }
}

void rtk_thread_list_reset(void)
{
    cm_rtk->active_node_index = NULL;
}

rtk_thread_t *rtk_thread_list_next(void)
{
    _RTK_TRACE_ENTRY();

    size_t sched_nest = rtk_sched_suspend();
    slist_node_t *active_node;
    rtk_thread_t *ret;

    if (cm_rtk->active_node_index == NULL)
    {
        active_node = slist_peek_head(&cm_rtk->slist_active);
    }
    else
    {
        active_node = slist_peek_next(cm_rtk->active_node_index);
    }

    rtk_sched_resume(sched_nest);

    if (active_node == NULL)
    {
        ret = NULL;
    }
    else
    {
        cm_rtk->active_node_index = active_node;
        struct rtk_thread_handle *thread = _RTK_CONTAINER_OF(active_node, struct rtk_thread_handle, active_node);
        ret = thread->thread_handle;
    }

    _RTK_TRACE_EXIT();
    return ret;
}

rtk_thread_t *rtk_thread_get_self(void)
{
    _RTK_TRACE_ENTRY();
    rtk_thread_t *ret = NULL;
    if (curr_thread_handle)
    {
        ret = curr_thread_handle->thread_handle;
    }
    _RTK_TRACE_EXIT();
    return ret;
}

rtk_thread_state_t rtk_thread_get_state(rtk_thread_t *thread_handle)
{
    _RTK_TRACE_ENTRY();

    struct rtk_thread_handle *thread;
    rtk_thread_state_t ret;

    if (thread_handle == NULL)
    {
        thread = curr_thread_handle;
    }
    else
    {
        thread = thread_handle->hdl;
    }

    if (thread == curr_thread_handle)
    {
        ret = THREAD_STATE_RUNNING;
    }
    else
    {
        ret = thread->curr_state;
    }

    _RTK_TRACE_EXIT();
    return ret;
}
void *rtk_thread_stack_base(rtk_thread_t *thread_handle)
{
    _RTK_TRACE_ENTRY();

    struct rtk_thread_handle *thread;
    if (thread_handle == NULL)
    {
        thread = curr_thread_handle;
    }
    else
    {
        thread = thread_handle->hdl;
    }

    _RTK_TRACE_EXIT();
    return thread->stack_base;
}

size_t rtk_thread_stack_size(rtk_thread_t *thread_handle)
{
    _RTK_TRACE_ENTRY();

    struct rtk_thread_handle *thread;
    if (thread_handle == NULL)
    {
        thread = curr_thread_handle;
    }
    else
    {
        thread = thread_handle->hdl;
    }

    _RTK_TRACE_EXIT();
    return thread->stack_size;
}

int rtk_thread_stack_used_size(rtk_thread_t *thread_handle)
{
    _RTK_TRACE_ENTRY();
    _RTK_CHECK_THREAD(thread_handle);

    size_t sched_nest = rtk_sched_suspend();

    int ret;
    struct rtk_thread_handle *thread;
    if (thread_handle == NULL)
    {
        thread = curr_thread_handle;
    }
    else
    {
        thread = thread_handle->hdl;
    }
    _RTK_CHECK_THREAD(&thread);

    int remain = _rtk_service_stack_remain(thread); // 设置的大小（此值包含了管理链头、完全堆入寄存器和用户创建线程时设置之和）
    if (remain < 0)
    {
        ret = remain;
    }
    else
    {
        ret = thread->stack_size - remain;
    }

    rtk_sched_resume(sched_nest);

    _RTK_TRACE_EXIT();
    return ret;
}

int rtk_thread_stack_empty_size(rtk_thread_t *thread_handle)
{
    _RTK_TRACE_ENTRY();

    struct rtk_thread_handle *thread;
    if (thread_handle == NULL)
    {
        thread = curr_thread_handle;
    }
    else
    {
        thread = thread_handle->hdl;
    }
    _RTK_CHECK_THREAD(&thread);

    size_t sched_nest = rtk_sched_suspend();

    int ret = _rtk_service_stack_remain(thread); // 设置的大小（此值包含了管理链头、完全堆入寄存器和用户创建线程时设置之和）

    rtk_sched_resume(sched_nest);

    _RTK_TRACE_EXIT();
    return ret;
}

char *rtk_thread_get_name(rtk_thread_t *thread_handle)
{
    _RTK_TRACE_ENTRY();

    struct rtk_thread_handle *thread;
    if (thread_handle == NULL)
    {
        thread = curr_thread_handle;
    }
    else
    {
        thread = thread_handle->hdl;
    }

    _RTK_TRACE_EXIT();
    return thread->name;
}

u8_t rtk_thread_get_slice_ticks(rtk_thread_t *thread_handle)
{
    _RTK_TRACE_ENTRY();

    struct rtk_thread_handle *thread;
    if (thread_handle == NULL)
    {
        thread = curr_thread_handle;
    }
    else
    {
        thread = thread_handle->hdl;
    }
    _RTK_CHECK_THREAD(&thread);

    _RTK_TRACE_EXIT();
    return thread->control.slice_ticks;
}

rtk_prior_t rtk_thread_get_priority(rtk_thread_t *thread_handle)
{
    _RTK_TRACE_ENTRY();

    struct rtk_thread_handle *thread;
    if (thread_handle == NULL)
    {
        thread = curr_thread_handle;
    }
    else
    {
        thread = thread_handle->hdl;
    }
    _RTK_CHECK_THREAD(&thread);

    _RTK_TRACE_EXIT();
    return thread->curr_prior;
}

void rtk_thread_sleep(rtk_tick_t ticks)
{
    _RTK_TRACE_ENTRY();
    _DO_RTK_CHECK_ISR();
    _RTK_CHECK_SWAP(ticks);

    struct rtk_thread_handle *self_thread = curr_thread_handle;
    if (ticks != 0)
    {
        _RTK_TICK_LIMIT(ticks);
        self_thread->wait_forever = 0;
        self_thread->wakeup_tick = cm_rtk->systime_tick + ticks;
        _rtk_list_atomic_sleep(self_thread);
    }
    else
    {
        _rtk_list_atomic_yield(self_thread);
    }

    _RTK_TRACE_EXIT();
}

void rtk_thread_sleep_until(rtk_tick_t ticks)
{
    _RTK_TRACE_ENTRY();
    _DO_RTK_CHECK_ISR();
    _RTK_CHECK_SWAP(ticks);

    struct rtk_thread_handle *thread = curr_thread_handle;
    thread->wakeup_tick += (cm_rtk->systime_tick - thread->wakeup_tick) / ticks * ticks + ticks;
    _rtk_list_atomic_sleep(thread);

    _RTK_TRACE_EXIT();
}

void rtk_thread_sleep_time(size_t hours,
                           size_t minute,
                           size_t second,
                           size_t milli)
{
    _RTK_TRACE_ENTRY();
    _DO_RTK_CHECK_ISR();

    rtk_tick_t ticks = (CONFIG_RTK_TICKS_HZ *                      // 每秒节拍数
                        (hours * 3600 +                            // 时
                         minute * 60 +                             // 分
                         second)) +                                // 秒
                       (milli * CONFIG_RTK_TICKS_HZ + 500) / 1000; // 节拍数
    _RTK_CHECK_SWAP(ticks);

    rtk_thread_sleep(ticks);

    _RTK_TRACE_EXIT();
}

void rtk_thread_yield(void)
{
    _RTK_TRACE_ENTRY();
    _DO_RTK_CHECK_ISR();
    _rtk_list_atomic_yield(curr_thread_handle);
    _RTK_TRACE_EXIT();
}

void rtk_thread_suspend(void)
{
    _RTK_TRACE_ENTRY();
    _DO_RTK_CHECK_ISR();
    rtk_thread_set_suspend(NULL);
    _RTK_TRACE_EXIT();
}

rtk_err_t rtk_thread_set_suspend(rtk_thread_t *thread_handle)
{
    _RTK_TRACE_ENTRY();

    struct rtk_thread_handle *thread;
    if (thread_handle == NULL)
    {
        thread = curr_thread_handle;
    }
    else
    {
        thread = thread_handle->hdl;
    }
    _RTK_CHECK_THREAD(&thread);

    _rtk_list_atomic_suspend(thread);

    _RTK_TRACE_EXIT();
    return RTK_OK;
}

rtk_err_t rtk_thread_resume(rtk_thread_t *thread_handle)
{
    _RTK_TRACE_ENTRY();

    struct rtk_thread_handle *thread;
    if (thread_handle == NULL)
    {
        thread = curr_thread_handle;
    }
    else
    {
        thread = thread_handle->hdl;
    }
    _RTK_CHECK_THREAD(&thread);

    _rtk_list_atomic_resume(thread);

    _RTK_TRACE_EXIT();
    return RTK_OK;
}

rtk_err_t rtk_thread_set_priority(rtk_thread_t *thread_handle, rtk_prior_t priority)
{
    _RTK_TRACE_ENTRY();

    struct rtk_thread_handle *thread;
    if (thread_handle == NULL)
    {
        thread = curr_thread_handle;
    }
    else
    {
        thread = thread_handle->hdl;
    }
    _RTK_CHECK_THREAD(&thread);

    size_t sched_nest = rtk_sched_suspend();

    if (priority < 0)
    {
        priority = CONFIG_RTK_MAX_PRIORITY + 1 + priority;
    }
    if (priority > CONFIG_RTK_MAX_PRIORITY)
    {
        _RTK_WRN("priority = %d > CONFIG_RTK_MAX_PRIORITY. Now Set to %d", priority, CONFIG_RTK_MAX_PRIORITY);
        priority = CONFIG_RTK_MAX_PRIORITY;
    }

    if (thread->control.priority != priority)
    {
        thread->control.priority = priority;
        if (thread->curr_state == THREAD_STATE_PENDING) // 线程在就绪状态
        {
            _rtk_list_atomic_pend(thread);
        }
        else if (thread->curr_state == THREAD_STATE_WAIT_MUTEX) // 线程在等待互斥量
        {
            _rtk_list_atomic_wait_mutex(thread);
        }
    }

    rtk_sched_resume(sched_nest);

    _RTK_TRACE_EXIT();
    return RTK_OK;
}

rtk_err_t rtk_thread_set_slice_ticks(rtk_thread_t *thread_handle, u8_t slice_ticks)
{
    _RTK_TRACE_ENTRY();

    struct rtk_thread_handle *thread;
    if (thread_handle == NULL)
    {
        thread = curr_thread_handle;
    }
    else
    {
        thread = thread_handle->hdl;
    }
    _RTK_CHECK_THREAD(&thread);

    thread->control.slice_ticks = slice_ticks;

    _RTK_TRACE_EXIT();
    return RTK_OK;
}

void rtk_thread_set_errno(int errno)
{
#if (CONFIG_RTK_POSIX_ERRNO == 1)
    curr_thread_handle->posix_errno = errno;
#endif
}

int rtk_thread_get_errno(void)
{
#if (CONFIG_RTK_POSIX_ERRNO == 1)
    return curr_thread_handle->posix_errno;
#else
    return 0;
#endif
}

bool rtk_thread_is_valid(rtk_thread_t *thread_handle)
{
    if (thread_handle == NULL)
    {
        return false;
    }

    _RTK_TRACE_ENTRY();

    struct rtk_thread_handle *thread = thread_handle->hdl;
    bool ret;

    if (rtk_heapk_is_valid(thread) == false)
    {
        ret = false;
    }
    else
    {
        ret = true;
    }

    _RTK_TRACE_EXIT();
    return ret;
}
